use crate::{
    models::{assets::AssetsModelDTO, user::NormalUserModel},
    services::assets_service::{AssetsService, DeleteAssetsReq},
    AppResult, PaginationQuery,
};
use actix_multipart::Multipart;
use actix_web::{web, HttpResponse};
use serde::{Deserialize, Serialize};

use super::OK_RESPONSE;
#[derive(Debug, Serialize, Deserialize)]
pub struct UploadFileCtrReq {
    pub o_id: Option<String>,
}

mod serde_default {
    pub fn draw_count() -> u64 {
        10
    }
}
mod ctrl_struct {
    pub use super::*;
    define_filter_request_struct!(SearchAllAssetsReq {});
}

async fn upload_file(
    assets_service: web::Data<AssetsService>,
    multipart: Multipart,
    user: Option<NormalUserModel>,
) -> AppResult<HttpResponse> {
    let res = assets_service
        .upload_assets(multipart, user.map(|u| u.id))
        .await?
        .iter()
        .map(|model| AssetsModelDTO::from(model.clone()))
        .collect::<Vec<_>>();
    Ok(HttpResponse::Ok().json(res))
}

async fn search_all_assets(
    assets_service: web::Data<AssetsService>,
    query: web::Query<PaginationQuery>,
    req: web::Json<ctrl_struct::SearchAllAssetsReq>,
) -> AppResult<HttpResponse> {
    let filter = req.get_filter_as_document_use_default();
    let res = assets_service.search_all_assets(&*query, filter).await?;
    Ok(HttpResponse::Ok().json(res.map_into::<AssetsModelDTO>()))
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteAssetsCtrlQuery {
    #[serde(default = "Default::default")]
    pub force: bool,
    pub assets_id: String,
}

async fn delete_assets(
    assets_service: web::Data<AssetsService>,
    query_req: web::Json<DeleteAssetsCtrlQuery>,
) -> AppResult<HttpResponse> {
    let query_req = query_req.into_inner();
    let assets_id = query_req.assets_id;
    let force = query_req.force;
    assets_service
        .delete_assets(&DeleteAssetsReq { assets_id, force })
        .await?;
    Ok(HttpResponse::Ok().json(OK_RESPONSE))
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrawAssetsCtrlQuery {
    #[serde(default = "serde_default::draw_count")]
    pub count: u64,
}
async fn draw_assets(
    assets_service: web::Data<AssetsService>,
    query_req: web::Query<DrawAssetsCtrlQuery>,
) -> AppResult<HttpResponse> {
    let res = assets_service
        .draw_assets(query_req.count)
        .await?
        .iter()
        .map(|v| AssetsModelDTO::from(v.clone()))
        .collect::<Vec<_>>();
    Ok(HttpResponse::Ok().json(res))
}
pub fn configure_assets_controller(config: &mut web::ServiceConfig) {
    config
        .service(web::resource("/draw").route(web::post().to(draw_assets)))
        .service(web::resource("/upload").route(web::post().to(upload_file)))
        .service(web::resource("/search").route(web::post().to(search_all_assets)))
        .service(web::resource("/delete").route(web::post().to(delete_assets)));
}
